package com.appspot.bibtable.view.html;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLEncoder;
import java.util.logging.Logger;

import com.appspot.bibtable.model.ReferenceEntity;
import com.appspot.bibtable.model.UserInfo;
import com.appspot.bibtable.model.format.CollectionFormatter;
import com.appspot.bibtable.model.format.HtmlEncodeFormatter;
import com.appspot.bibtable.model.format.OutputFormatter;
import com.appspot.bibtable.model.format.YearFormatter;
import com.appspot.bibtable.util.HtmlUtility;
import com.google.appengine.api.datastore.Category;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

public class ReferenceListTable extends HtmlTable
{
	private static final Logger logger = Logger.getLogger(ReferenceListTable.class.getName());

	private static final OutputFormatter defaultFormatter = new HtmlEncodeFormatter();
	private static final OutputFormatter authorFormatter = new CollectionFormatter(new OutputFormatter()
	{
		@Override
		public String format(Object object)
		{
			String author = (String)object;
			String encodedTag = author;
			try
			{
				encodedTag = URLEncoder.encode(author, "UTF-8");
			}
			catch (UnsupportedEncodingException ex)
			{
				logger.severe("UTF-8 encoding is not supported.");
			}
			return "<a href=\"/search?query=author:%22" + encodedTag + "%22\">" + HtmlUtility.encode(author) + "</a>";
		}
	});
	private static final OutputFormatter yearFormatter = new YearFormatter();
	private static final OutputFormatter tagFormatter = new CollectionFormatter(new OutputFormatter()
	{
		@Override
		public String format(Object object)
		{
			String tag = ((Category)object).getCategory();
			String encodedTag = tag;
			try
			{
				encodedTag = URLEncoder.encode(tag, "UTF-8");
			}
			catch (UnsupportedEncodingException ex)
			{
				logger.severe("UTF-8 encoding is not supported.");
			}
			return "<a href=\"/search?query=tag:%22" + encodedTag + "%22\">" + HtmlUtility.encode(tag) + "</a>";
		}
	});

	private UserInfo userInfo;

	@Override
	public void startTable(Writer writer) throws IOException
	{
		super.startTable(writer);
		writer.write("<col class=\"checkbox-column\" />");
		writer.write("<col class=\"toolbox-column\" />");
		writer.write("<col class=\"type-column\" />");
		writer.write("<col class=\"title-column\" />");
		writer.write("<col class=\"author-column\" />");
		writer.write("<col class=\"published-column\" />");
		writer.write("<col class=\"tag-column\" />");
		writer.write("<col class=\"lastModified-column\" />");
		writer.write("<thead>");
		writer.write("<tr>");
		writer.write("<th id=\"allkey\"></th><th></th><th>Type</th><th>Title</th><th>Author</th><th>Published</th><th>Tag</th><th>Last Modified</th>");
		writer.write("</tr>");
		writer.write("</thead>");
		writer.write("<tbody>");
	}

	@Override
	public void endTable(Writer writer) throws IOException
	{
		writer.write("</tbody>");
		super.endTable(writer);
	}

	@Override
	public void addReference(ReferenceEntity entity, Writer writer) throws IOException
	{
		Key key = entity.getKey();
		String keyString = KeyFactory.keyToString(key);

		UserInfo userInfo = getUserInfo();

		String type = defaultFormatter.format(entity.getType());
		String title = defaultFormatter.format(entity.getTitle());
		String author = authorFormatter.format(entity.getAuthor());
		String publish = yearFormatter.format(entity.getPublished());
		String tag = tagFormatter.format(entity.getTag());
		String lastModified = defaultFormatter.format(entity.getLastModified());

		author = trimBracket(author);
		tag = trimBracket(tag);

		writer.write("<tr>");
		writer.write("<td><input type=\"checkbox\" name=\"key\" value=\"" + keyString + "\" /></td>");
		writer.write("<td class=\"toolbox\">");
		if (userInfo != null)
		{
			if (userInfo.isBookmarking(key))
			{
				writer.write("<a href=\"/unbookmark/" + keyString + "\" class=\"bookmark\">");
				writer.write("<img src=\"/themes/default/icons/bookmark.png\" width=\"16\" height=\"16\" alt=\"bookmarked\" title=\"Click to unbookmark\" />");
				writer.write("</a>");
			}
			else
			{
				writer.write("<a href=\"/bookmark/" + keyString + "\" class=\"bookmark\">");
				writer.write("<img src=\"/themes/default/icons/unbookmark.png\" width=\"16\" height=\"16\" alt=\"not bookmarked\" title=\"Click to bookmark\" />");
				writer.write("</a>");
			}
			writer.write("<a href=\"/edit/" + keyString + "\" class=\"edit\">");
			writer.write("<img src=\"/themes/default/icons/edit.png\" width=\"16\" height=\"16\" alt=\"edit\" title=\"Click to edit\" />");
			writer.write("</a>");
		}
		else
		{
			writer.write("<img src=\"/themes/default/icons/bookmark-disabled.png\" width=\"16\" height=\"16\" alt=\"You cannot bookmark item before sign-in.\" />");
			writer.write("<img src=\"/themes/default/icons/edit-disabled.png\" width=\"16\" height=\"16\" alt=\"You cannot edit item before sign-in.\" />");
		}
		writer.write("<a href=\"/detail/" + keyString + "\" class=\"edit\">");
		writer.write("<img src=\"/themes/default/icons/detail.png\" width=\"16\" height=\"16\" alt=\"detail\" title=\"Click to see detail\" />");
		writer.write("</a>");
		writer.write("</td>");
		writer.write("<td class=\"reference-type\">" + type + "</td>");
		writer.write("<td class=\"reference-title\">" + title + "</td>");
		writer.write("<td class=\"reference-author\">" + author + "</td>");
		writer.write("<td class=\"reference-year\">" + publish + "</td>");
		writer.write("<td class=\"reference-tag\">" + tag + "</td>");
		writer.write("<td class=\"reference-lastModified\">" + lastModified + "</td>");
		writer.write("</tr>");
	}
	
	private static String trimBracket(String listString)
	{
		if (listString == null)
		{
			return null;
		}
		return listString.substring(1, listString.length() - 1);
	}

	public UserInfo getUserInfo()
	{
		return userInfo;
	}

	public void setUserInfo(UserInfo userInfo)
	{
		this.userInfo = userInfo;
	}
}
